Load libraries and file paths

library("plyr")
library("dplyr")
library("ggplot2")
library(R.utils)
library(gghighlight)
library(ggman)
library(ggtext)
library(patchwork)
library(plotrix)
library(qqman)
library(qvalue)
library(reshape2)
library(tidyr)
library(zoo)
library(infer)
options(dplyr.summarise.inform = FALSE)
library(bigsnpr)
library("wesanderson")
library("directlabels")
library(OutFLANK)
library(adegenet)
library(poppr)
library(vcfR)
library(stringr)
library(matrixStats)
library(purrr)
library(scales) 

Nucleotide diversity

Nucleotide diversity (often referred to using the symbol π) is the average pairwise difference between all possible pairs of individuals in your sample. It is a very intuitive and simple measure of genetic diversity, and is accurately estimated even with very few samples. A formal definition is here.

We can obtain the nucleotide diversity (π) from our VCF file using vcftools software. In our case we will collect the π value from each 10 kb (10,000 bp) window of the genome.

NB: vcftools is a very flexible tool for analyzing, manipulating VCF files. It can do many other wonderful things. The vcftools manual is on github here (https://vcftools.sourceforge.net/man_latest.html).

Breaking up pi by treatment type?

I believe that an important step would be to compare nucleotide diversity between the different treatment groups. The following code present information for all treatment groups and compares it to each individual treatment group.

Start of modified workflow

Setup

The following was run on the command line

# Make ROD_CADO_working directory in home
mkdir ROD_CADO_working
cd ROD_CADO_working
# Make Nucleotide_diversity directory
mkdir ROD_CADO_working
# create popmap file with sample and treatment names
cp /home/Shared_Data/ROD_CADO/analysis/popmap popmap
# manually add in treatment names to popmap file (w/ code)
head treat_popmap 

C1_2 con-con C1_4 con-con C1_5 con-con C1_6 con-con C1_7 con-con C1_8 con-con C1_9 con-con C2_10 con-con C2_11 con-con C2_2 con-con

Subsetting popmap groups

Create treatment specific files containing a single column of all of the sample names within that treatment

awk '$2 == "con-con" {print $1}' treat_popmap > con-con.txt | awk '$2 == "str-con" {print $1}' treat_popmap > str-con.txt | awk '$2 == "con-rod" {print $1}' treat_popmap > con-rod.txt | awk '$2 == "str-rod" {print $1}' treat_popmap > str-rod.txt

Run VCF tools PI window

#bcftools view --threads 20 -S SNP.TRSdp10g1.FIL.vcf | vcftools --vcf -  --window-pi 10000 --out ROD.CADO.all.pi

# For con-con
# Step 1: Filter VCF for population subset
vcftools --gzvcf SNP.TRSdp10g1.FIL.vcf.gz --keep con-con.txt --recode --recode-INFO-all --out temp_concon_filtered

# Step 2: bgzip output
bgzip temp_concon_filtered.recode.vcf

# Step 3: Calculate windowed pi
vcftools --gzvcf temp_concon.filtered.recode.vcf.gz --window-pi 10000 --out ROD.CADO.con-con.pi.windowed.pi

# For str-con
# Step 1: Filter VCF for population subset
vcftools --gzvcf SNP.TRSdp10g1.FIL.vcf.gz --keep popmap_files/str-con.txt --recode --recode-INFO-all --out temp_strcon_filtered

# Step 2: bgzip output
bgzip temp_strcon_filtered.recode.vcf

# Step 3: # Step 3: Calculate windowed pi
vcftools --gzvcf temp_strcon_filtered.recode.vcf.gz --window-pi 10000 --out ROD.CADO.str-con.pi.windowed.pi

# For con-rod
# Step 1: Filter VCF for population subset
vcftools --gzvcf SNP.TRSdp10g1.FIL.vcf --keep popmap_files/con-rod.txt --recode --recode-INFO-all --out temp_conrod_filtered

# Step 2: bgzip output
bgzip temp_conrod_filtered.recode.vcf

# Step 3: Calculate windowed pi
vcftools --gzvcf temp_conrod_filtered.recode.vcf.gz --window-pi 10000 --out ROD.CADO.con-rod.pi.windowed.pi

# For str-rod
# Step 1: Filter VCF for population subset
vcftools --gzvcf SNP.TRSdp10g1.FIL.vcf --keep popmap_files/str-rod.txt --recode --recode-INFO-all --out temp_strrod_filtered

# Step 2: bgzip output
bgzip temp_strrod_filtered.recode.vcf

# Step 3: Calculate windowed pi
vcftools --gzvcf temp_strrod_filtered.recode.vcf.gz --window-pi 10000 --out ROD.CADO.str-rod.pi.windowed.pi

Make script with loop using ChatGPT

Make script

#!/bin/bash

VCF=SNP.TRSdp10g1.FIL.vcf.gz
POPS=("con-con" "str-con" "con-rod" "str-rod")

for POP in "${POPS[@]}"; do
    echo "Processing $POP..."

    KEEP="popmap_files/${POP}.txt"
    OUT_PREFIX="temp_${POP//-}"
    REC_VCF="${OUT_PREFIX}.recode.vcf"
    REC_VCFGZ="${REC_VCF}.gz"
    OUTPUT_PI="ROD.CADO.${POP}.pi.windowed.pi"

    # Step 1: Filter and recode
    vcftools --gzvcf "$VCF" \
        --keep "$KEEP" \
        --recode --recode-INFO-all \
        --out "$OUT_PREFIX"

    # Step 2: Compress VCF and remove uncompressed
    bgzip "$REC_VCF"
    rm "$REC_VCF"

    # Step 3: Calculate windowed pi
    vcftools --gzvcf "$REC_VCFGZ" \
        --window-pi 10000 \
        --out "$OUTPUT_PI"

    # Step 4: Clean up compressed VCF
    rm "$REC_VCFGZ"

    echo "Finished processing $POP"
    echo "---------------------------"
done

Make executable

chmod +x run_pi_calculations.sh

Run in tmux

# Run in tmux
tmux new -s pi_calc
# Reattach later
tmux attach-session -t pi_calc

Load dataframe

pi.all.dataframe<-read.table("/home/Shared_Data/ROD_CADO/analysis/raw.vcf/ROD.CADO.all.pi.windowed.pi", sep="\t", header=T)
pi.concon.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.con-con.pi.windowed.pi.windowed.pi", sep="\t", header=T)
pi.conrod.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.con-rod.pi.windowed.pi.windowed.pi", sep="\t", header=T)
pi.strcon.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.str-con.pi.windowed.pi.windowed.pi", sep="\t", header=T)
pi.strrod.dataframe<-read.table("/home/jgreen/ROD_CADO_working/Nucleotide_diversity/ROD.CADO.str-rod.pi.windowed.pi.windowed.pi", sep="\t", header=T)

Color palette

#Here is the color pallette that we will use for everything:

col_pal <- c("#0072B2", "#56B4E9", "#E69F00", "#F0E442")

#Let's factor treatments as follows:

df$TREAT <- factor(df$TREAT, levels=c("CONCON", "STRCON", "CONROD", "STRROD"))

Modify CHROM column in dataframe

pi.all.dataframe %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
  mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10"))  -> pi.all.df
pi.all.df$CHROM <- as.factor(pi.all.df$CHROM)

pi.concon.dataframe %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
  mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10"))  -> pi.concon.df
pi.concon.df$CHROM <- as.factor(pi.concon.df$CHROM)

pi.conrod.dataframe %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
  mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10"))  -> pi.conrod.df
pi.conrod.df$CHROM <- as.factor(pi.conrod.df$CHROM)

pi.strcon.dataframe %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
  mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10"))  -> pi.strcon.df
pi.strcon.df$CHROM <- as.factor(pi.strcon.df$CHROM)

pi.strrod.dataframe %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035780.1", "1")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035781.1", "2")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035782.1", "3")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035783.1", "4")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035784.1", "5")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035785.1", "6")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035786.1", "7")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035787.1", "8")) %>%
  mutate(CHROM = str_replace(CHROM, "NC_035788.1", "9")) %>% 
  mutate(CHROM = str_replace(CHROM, "NC_035789.1", "10"))  -> pi.strrod.df
pi.strrod.df$CHROM <- as.factor(pi.strrod.df$CHROM)

For loop to replace previous dataframe manipulation


# Create named vector to map chromosome names
chrom_map <- setNames(as.character(1:10), paste0("NC_03578", 0:9, ".1"))

# List of original dataframe names (as strings)
input_names <- c(
  "pi.all.dataframe",
  "pi.concon.dataframe",
  "pi.conrod.dataframe",
  "pi.strcon.dataframe",
  "pi.strrod.dataframe"
)

# Corresponding output dataframe names
output_names <- c(
  "pi.all.df",
  "pi.concon.df",
  "pi.conrod.df",
  "pi.strcon.df",
  "pi.strrod.df"
)

# Loop through each dataframe
for (i in seq_along(input_names)) {
  df <- get(input_names[i])  # retrieve the dataframe by name
  
  # Replace chromosome names
  for (old in names(chrom_map)) {
    df <- df %>% mutate(CHROM = str_replace(CHROM, old, chrom_map[[old]]))
  }
  
  # Convert to factor
  df$CHROM <- as.factor(df$CHROM)
  
  # Assign to new name in global environment
  assign(output_names[i], df)
}

Descriptive statistics

summary(pi.all.df)
by(pi.all.df, pi.all.df$CHROM, summary)
cor(pi.all.df$N_VARIANTS, pi.all.df$PI)

summary(pi.concon.df)
by(pi.concon.df, pi.concon.df$CHROM, summary)
cor(pi.concon.df$N_VARIANTS, pi.concon.df$PI)

summary(pi.conrod.df)
by(pi.conrod.df, pi.conrod.df$CHROM, summary)
cor(pi.conrod.df$N_VARIANTS, pi.conrod.df$PI)

summary(pi.strcon.df)
by(pi.strcon.df, pi.strcon.df$CHROM, summary)
cor(pi.strcon.df$N_VARIANTS, pi.strcon.df$PI)

summary(pi.strrod.df)
by(pi.strrod.df, pi.strrod.df$CHROM, summary)
cor(pi.strrod.df$N_VARIANTS, pi.strrod.df$PI)

New loop and plotting for statistics

col_pal <- c(
  "ALL" = "gray70",
  "CONCON" = "#0072B2", 
  "STRCON" = "#56B4E9", 
  "CONROD" = "#E69F00", 
  "STRROD" = "#F0E442"
)

df_names <- c("pi.all.df", "pi.concon.df", "pi.strcon.df", "pi.conrod.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "STRCON", "CONROD", "STRROD")
chrom_levels <- as.character(1:10)

summary_list <- list()

for (i in seq_along(df_names)) {
  df <- get(df_names[i])
  treat <- df_labels[i]
  
  df$TREAT <- factor(treat, levels = names(col_pal))
  
  chrom_summary <- df %>%
    group_by(CHROM, TREAT) %>%
    summarise(
      mean_PI = mean(PI, na.rm = TRUE),
      se_PI = sd(PI, na.rm = TRUE) / sqrt(n()),
      mean_N_VARIANTS = mean(N_VARIANTS, na.rm = TRUE),
      se_N_VARIANTS = sd(N_VARIANTS, na.rm = TRUE) / sqrt(n()),
      .groups = "drop"
    ) %>%
    mutate(CHROM = factor(CHROM, levels = chrom_levels))
  
  summary_list[[i]] <- chrom_summary
}

summary_df <- bind_rows(summary_list)

mean_pi_plot <- ggplot(summary_df, aes(x = CHROM, y = mean_PI, fill = TREAT)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.8)) +
  geom_errorbar(aes(ymin = mean_PI - se_PI, ymax = mean_PI + se_PI),
                position = position_dodge(width = 0.8), width = 0.2) +
  scale_fill_manual(values = col_pal, name = "Treatment") +
  labs(title = "Mean PI per Chromosome", x = "Chromosome", y = "Mean PI") +
  theme_minimal()

mean_n_plot <- ggplot(summary_df, aes(x = CHROM, y = mean_N_VARIANTS, fill = TREAT)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.8)) +
  geom_errorbar(aes(ymin = mean_N_VARIANTS - se_N_VARIANTS, ymax = mean_N_VARIANTS + se_N_VARIANTS),
                position = position_dodge(width = 0.8), width = 0.2) +
  scale_fill_manual(values = col_pal, name = "Treatment") +
  labs(title = "Mean number of variants per Chromosome", x = "Chromosome", y = "Mean # variants") +
  theme_minimal()

print(mean_pi_plot)

print(mean_n_plot)

ggsave("mean_pi_plot.png", plot = mean_pi_plot, width = 10, height = 6, dpi = 300)
ggsave("mean_n_variants_plot.png", plot = mean_n_plot, width = 10, height = 6, dpi = 300)

Correlation visualizations

for (i in seq_along(df_names)) {
  df <- get(df_names[i])
  label <- df_labels[i]
  
  p <- ggplot(df, aes(x = N_VARIANTS, y = PI)) +
    geom_point(alpha = 0.4) +
    geom_smooth(method = "lm", se = FALSE, color = "blue") +
    labs(title = paste("Correlation: PI vs # variants —", label),
         x = "N_VARIANTS",
         y = "PI") +
    theme_minimal()
  
  print(p)
}

Table of correlations

cor_table <- tibble(
  dataset = df_labels,
  correlation = map_dbl(df_names, ~ cor(get(.x)$N_VARIANTS, get(.x)$PI, use = "complete.obs"))
)

print(cor_table)

Plot PI by chromosome

ggplot(pi.all.df, aes(x=CHROM, y=PI,))+
  geom_violin(aes(color=CHROM,fill=CHROM))+
  geom_boxplot(aes(fill=CHROM), width=0.1,outlier.shape = 23, outlier.color = "black")+
  stat_summary(fun=mean, geom="point", shape=23, size=2)+
  scale_fill_brewer(palette = "Paired")+
  theme_classic()

Plot PI by chromosome loop

# List of dataframes and labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("All", "ConCon", "ConRod", "StrCon", "StrRod")

# Standard chromosome order
chrom_levels <- as.character(1:10)

# Combine all into one dataframe
combined_df <- purrr::map2_dfr(df_names, df_labels, function(df_name, label) {
  df <- get(df_name)
  df %>%
    mutate(
      dataset = label,
      CHROM = factor(CHROM, levels = chrom_levels)
    )
})

# Faceted violin + boxplot
ggplot(combined_df, aes(x = CHROM, y = PI)) +
  geom_violin(aes(color = CHROM, fill = CHROM), trim = FALSE) +
  geom_boxplot(aes(fill = CHROM), width = 0.1, outlier.shape = 23, outlier.color = "black") +
  stat_summary(fun = mean, geom = "point", shape = 23, size = 2) +
  scale_fill_brewer(palette = "Paired") +
  labs(title = "PI Distribution by Chromosome (Faceted by Dataset)",
       x = "Chromosome", y = "PI") +
  facet_wrap(~ dataset, ncol = 2) +
  theme_classic() +
  theme(legend.position = "none")

Smaller visualizations

hist(mydf$PI,br=40)

boxplot(mydf$PI, ylab="Nuc Diversity")

Plot By position

ggplot(pi.all.df, aes(x=BIN_START, y=PI, color=CHROM))+
  geom_point()+
  scale_fill_brewer(palette = "Paired") +
  scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
  facet_wrap(~CHROM)+
  theme_classic()

Loop for plot by position

# Define dataframe names and labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "CONROD", "STRCON", "STRROD")

# Get global PI range
all_pi_values <- unlist(lapply(df_names, function(x) get(x)$PI))
global_ymin <- min(all_pi_values, na.rm = TRUE)
global_ymax <- max(all_pi_values, na.rm = TRUE)

# Loop over dataframes
for (i in seq_along(df_names)) {
  df <- get(df_names[i])
  label <- df_labels[i]
  
  # Ensure CHROM is a factor ordered from 1 to 10
  df$CHROM <- factor(df$CHROM, levels = as.character(1:10))
  
  p <- ggplot(df, aes(x = BIN_START, y = PI, color = CHROM)) +
    geom_point() +
    facet_wrap(~CHROM) +
    scale_fill_brewer(palette = "Paired") +
    scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +  # Human readable x-axis
    ylim(global_ymin, global_ymax) +  # Same y-axis for all plots
    theme_classic() +
    labs(title = paste("PI vs BIN_START -", label),
         x = "BIN_START (millions)",
         y = "PI")
  
  print(p)
  
  ggsave(filename = paste0("PI_vs_BIN_START_", label, ".png"),
         plot = p, width = 10, height = 6, dpi = 300)
}

Facet wrap chromosome showing them across different treatment types

# Define dataframe names and labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "CONROD", "STRCON", "STRROD")

# Custom color palette
col_pal <- c(
  "ALL" = "gray70",
  "CONCON" = "#0072B2", 
  "STRCON" = "#56B4E9", 
  "CONROD" = "#E69F00", 
  "STRROD" = "#F0E442"
)

# Combine all data into one dataframe with treatment labels
all_data <- bind_rows(lapply(seq_along(df_names), function(i) {
  df <- get(df_names[i])
  df$Treatment <- df_labels[i]
  df
}))

# Set CHROM and Treatment as ordered factors
all_data$CHROM <- factor(all_data$CHROM, levels = as.character(1:10))
all_data$Treatment <- factor(all_data$Treatment, levels = df_labels)

# Get global PI range
global_ymin <- min(all_data$PI, na.rm = TRUE)
global_ymax <- max(all_data$PI, na.rm = TRUE)

# Loop through chromosomes 1 to 10
for (chr in 1:10) {
  chr_str <- as.character(chr)
  chr_data <- filter(all_data, CHROM == chr_str)
  
  p <- ggplot(chr_data, aes(x = BIN_START, y = PI, color = Treatment)) +
    geom_point(alpha = 0.6, size = 0.5) +
    facet_wrap(~Treatment, nrow = 1) +
    scale_color_manual(values = col_pal) +
    scale_x_continuous(labels = label_number(scale = 1e-6, suffix = "M")) +
    ylim(global_ymin, global_ymax) +
    theme_classic() +
    labs(
      title = paste("Chromosome", chr, "- PI across Treatment Types"),
      x = "BIN_START (millions)",
      y = "PI"
    )
  
  print(p)
  
  ggsave(
    filename = paste0("PI_chr", chr, "_across_treatments.png"),
    plot = p,
    width = 16,
    height = 4,
    dpi = 300
  )
}

Only chromosome 1

# Subset by chrom
mydf.chr1 <- mydf[which(mydf$CHROM=="1"),]

ggplot(mydf.chr1, aes(x=BIN_START, y=PI))+
  geom_point()+
  theme_classic()
# List of treatment data frames and their labels
df_names <- c("pi.all.df", "pi.concon.df", "pi.conrod.df", "pi.strcon.df", "pi.strrod.df")
df_labels <- c("ALL", "CONCON", "CONROD", "STRCON", "STRROD")

# Step 1: Calculate global PI range across all dataframes
all_pi_values <- unlist(lapply(df_names, function(x) get(x)$PI))
global_ymin <- min(all_pi_values, na.rm = TRUE)
global_ymax <- max(all_pi_values, na.rm = TRUE)

# Step 2: Create plots and save as PNGs
for (j in seq_along(df_names)) {
  df <- get(df_names[j])
  label <- df_labels[j]
  
  for (i in 1:10) {
    chr_data <- df[df$CHROM == as.character(i), ]
    
    p <- ggplot(chr_data, aes(x = BIN_START, y = PI)) +
      geom_point() +
      theme_classic() +
      ggtitle(paste("Treatment:", label, "- Chromosome", i)) +
      labs(x = "BIN_START", y = "PI") +
      ylim(global_ymin, global_ymax)
    
    filename <- paste0("PI_", label, "_chr", i, ".png")
    ggsave(filename = filename, plot = p, width = 8, height = 5, dpi = 300)
  }
}

Runs of homozygosity

Runs of homozygosity (ROH) are contiguous lengths of homozygous genotypes that are present in an individual due to parents transmitting identical haplotypes to their offspring.

The potential of predicting or estimating individual autozygosity for a subpopulation is the proportion of the autosomal genome above a specified length, termed Froh.

This technique can be used to identify the genomic footprint of inbreeding in conservation programs, as organisms that have undergone recent inbreeding will exhibit long runs of homozygosity. The effect of inbreeding in the resulting sub-populations could be studied by measuring the runs of homozygosity in different individuals.

Start ROH workflow

vcftools --vcf SNP.TRSdp10g1.FIL.vcf --LROH --out ROD.CADO.all.LROH
LS0tCnRpdGxlOiAiR2VuZXRpYyBEaXZlcnNpdHkgd29yayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICczJwogIGh0bWxfZG9jdW1lbnQ6CiAgICBrZWVwX21kOiBUUlVFCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgcm9vdF9kaXIgPSAiL2hvbWUvU2hhcmVkX0RhdGEvUk9EX0NBRE8vYW5hbHlzaXMvcmF3LnZjZi9maWx0ZXJlZCIpCmBgYAoKIyBMb2FkIGxpYnJhcmllcyBhbmQgZmlsZSBwYXRocwpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSgicGx5ciIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgiZ2dwbG90MiIpCmxpYnJhcnkoUi51dGlscykKbGlicmFyeShnZ2hpZ2hsaWdodCkKbGlicmFyeShnZ21hbikKbGlicmFyeShnZ3RleHQpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHBsb3RyaXgpCmxpYnJhcnkocXFtYW4pCmxpYnJhcnkocXZhbHVlKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHpvbykKbGlicmFyeShpbmZlcikKb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpCmxpYnJhcnkoYmlnc25wcikKbGlicmFyeSgid2VzYW5kZXJzb24iKQpsaWJyYXJ5KCJkaXJlY3RsYWJlbHMiKQpsaWJyYXJ5KE91dEZMQU5LKQpsaWJyYXJ5KGFkZWdlbmV0KQpsaWJyYXJ5KHBvcHByKQpsaWJyYXJ5KHZjZlIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShtYXRyaXhTdGF0cykKbGlicmFyeShwdXJycikKbGlicmFyeShzY2FsZXMpIApgYGAKCiMgTnVjbGVvdGlkZSBkaXZlcnNpdHkKCk51Y2xlb3RpZGUgZGl2ZXJzaXR5IChvZnRlbiByZWZlcnJlZCB0byB1c2luZyB0aGUgc3ltYm9sIM+AKSBpcyB0aGUgYXZlcmFnZSBwYWlyd2lzZSBkaWZmZXJlbmNlIGJldHdlZW4gYWxsIHBvc3NpYmxlIHBhaXJzIG9mIGluZGl2aWR1YWxzIGluIHlvdXIgc2FtcGxlLiBJdCBpcyBhIHZlcnkgaW50dWl0aXZlIGFuZCBzaW1wbGUgbWVhc3VyZSBvZiBnZW5ldGljIGRpdmVyc2l0eSwgYW5kIGlzIGFjY3VyYXRlbHkgZXN0aW1hdGVkIGV2ZW4gd2l0aCB2ZXJ5IGZldyBzYW1wbGVzLiBBIGZvcm1hbCBkZWZpbml0aW9uIGlzIGhlcmUuCgpXZSBjYW4gb2J0YWluIHRoZSBudWNsZW90aWRlIGRpdmVyc2l0eSAoz4ApIGZyb20gb3VyIFZDRiBmaWxlIHVzaW5nIHZjZnRvb2xzIHNvZnR3YXJlLiBJbiBvdXIgY2FzZSB3ZSB3aWxsIGNvbGxlY3QgdGhlIM+AIHZhbHVlIGZyb20gZWFjaCAxMCBrYiAoMTAsMDAwIGJwKSB3aW5kb3cgb2YgdGhlIGdlbm9tZS4KCk5COiB2Y2Z0b29scyBpcyBhIHZlcnkgZmxleGlibGUgdG9vbCBmb3IgYW5hbHl6aW5nLCBtYW5pcHVsYXRpbmcgVkNGIGZpbGVzLiBJdCBjYW4gZG8gbWFueSBvdGhlciB3b25kZXJmdWwgdGhpbmdzLiBUaGUgdmNmdG9vbHMgbWFudWFsIGlzIG9uIGdpdGh1YiBoZXJlIChodHRwczovL3ZjZnRvb2xzLnNvdXJjZWZvcmdlLm5ldC9tYW5fbGF0ZXN0Lmh0bWwpLgoKIyMjIEJyZWFraW5nIHVwIHBpIGJ5IHRyZWF0bWVudCB0eXBlPwoKSSBiZWxpZXZlIHRoYXQgYW4gaW1wb3J0YW50IHN0ZXAgd291bGQgYmUgdG8gY29tcGFyZSBudWNsZW90aWRlIGRpdmVyc2l0eSBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgdHJlYXRtZW50IGdyb3Vwcy4gVGhlIGZvbGxvd2luZyBjb2RlIHByZXNlbnQgaW5mb3JtYXRpb24gZm9yIGFsbCB0cmVhdG1lbnQgZ3JvdXBzIGFuZCBjb21wYXJlcyBpdCB0byBlYWNoIGluZGl2aWR1YWwgdHJlYXRtZW50IGdyb3VwLgoKIyMgU3RhcnQgb2YgbW9kaWZpZWQgd29ya2Zsb3cKCiMjIFNldHVwIAoKVGhlIGZvbGxvd2luZyB3YXMgcnVuIG9uIHRoZSBjb21tYW5kIGxpbmUKYGBge2Jhc2h9CiMgTWFrZSBST0RfQ0FET193b3JraW5nIGRpcmVjdG9yeSBpbiBob21lCm1rZGlyIFJPRF9DQURPX3dvcmtpbmcKY2QgUk9EX0NBRE9fd29ya2luZwojIE1ha2UgTnVjbGVvdGlkZV9kaXZlcnNpdHkgZGlyZWN0b3J5Cm1rZGlyIFJPRF9DQURPX3dvcmtpbmcKIyBjcmVhdGUgcG9wbWFwIGZpbGUgd2l0aCBzYW1wbGUgYW5kIHRyZWF0bWVudCBuYW1lcwpjcCAvaG9tZS9TaGFyZWRfRGF0YS9ST0RfQ0FETy9hbmFseXNpcy9wb3BtYXAgcG9wbWFwCiMgbWFudWFsbHkgYWRkIGluIHRyZWF0bWVudCBuYW1lcyB0byBwb3BtYXAgZmlsZSAody8gY29kZSkKaGVhZCB0cmVhdF9wb3BtYXAgCmBgYApDMV8yICAgIGNvbi1jb24KQzFfNCAgICBjb24tY29uCkMxXzUgICAgY29uLWNvbgpDMV82ICAgIGNvbi1jb24KQzFfNyAgICBjb24tY29uCkMxXzggICAgY29uLWNvbgpDMV85ICAgIGNvbi1jb24KQzJfMTAgICBjb24tY29uCkMyXzExICAgY29uLWNvbgpDMl8yICAgIGNvbi1jb24KCiMgU3Vic2V0dGluZyBwb3BtYXAgZ3JvdXBzCkNyZWF0ZSB0cmVhdG1lbnQgc3BlY2lmaWMgZmlsZXMgY29udGFpbmluZyBhIHNpbmdsZSBjb2x1bW4gb2YgYWxsIG9mIHRoZSBzYW1wbGUgbmFtZXMgd2l0aGluIHRoYXQgdHJlYXRtZW50CmBgYHtiYXNofQphd2sgJyQyID09ICJjb24tY29uIiB7cHJpbnQgJDF9JyB0cmVhdF9wb3BtYXAgPiBjb24tY29uLnR4dCB8IGF3ayAnJDIgPT0gInN0ci1jb24iIHtwcmludCAkMX0nIHRyZWF0X3BvcG1hcCA+IHN0ci1jb24udHh0IHwgYXdrICckMiA9PSAiY29uLXJvZCIge3ByaW50ICQxfScgdHJlYXRfcG9wbWFwID4gY29uLXJvZC50eHQgfCBhd2sgJyQyID09ICJzdHItcm9kIiB7cHJpbnQgJDF9JyB0cmVhdF9wb3BtYXAgPiBzdHItcm9kLnR4dApgYGAKCiMjIyBSdW4gVkNGIHRvb2xzIFBJIHdpbmRvdwpgYGB7YmFzaCBldmFsID0gRkFMU0V9CiNiY2Z0b29scyB2aWV3IC0tdGhyZWFkcyAyMCAtUyBTTlAuVFJTZHAxMGcxLkZJTC52Y2YgfCB2Y2Z0b29scyAtLXZjZiAtICAtLXdpbmRvdy1waSAxMDAwMCAtLW91dCBST0QuQ0FETy5hbGwucGkKCiMgRm9yIGNvbi1jb24KIyBTdGVwIDE6IEZpbHRlciBWQ0YgZm9yIHBvcHVsYXRpb24gc3Vic2V0CnZjZnRvb2xzIC0tZ3p2Y2YgU05QLlRSU2RwMTBnMS5GSUwudmNmLmd6IC0ta2VlcCBjb24tY29uLnR4dCAtLXJlY29kZSAtLXJlY29kZS1JTkZPLWFsbCAtLW91dCB0ZW1wX2NvbmNvbl9maWx0ZXJlZAoKIyBTdGVwIDI6IGJnemlwIG91dHB1dApiZ3ppcCB0ZW1wX2NvbmNvbl9maWx0ZXJlZC5yZWNvZGUudmNmCgojIFN0ZXAgMzogQ2FsY3VsYXRlIHdpbmRvd2VkIHBpCnZjZnRvb2xzIC0tZ3p2Y2YgdGVtcF9jb25jb24uZmlsdGVyZWQucmVjb2RlLnZjZi5neiAtLXdpbmRvdy1waSAxMDAwMCAtLW91dCBST0QuQ0FETy5jb24tY29uLnBpLndpbmRvd2VkLnBpCgojIEZvciBzdHItY29uCiMgU3RlcCAxOiBGaWx0ZXIgVkNGIGZvciBwb3B1bGF0aW9uIHN1YnNldAp2Y2Z0b29scyAtLWd6dmNmIFNOUC5UUlNkcDEwZzEuRklMLnZjZi5neiAtLWtlZXAgcG9wbWFwX2ZpbGVzL3N0ci1jb24udHh0IC0tcmVjb2RlIC0tcmVjb2RlLUlORk8tYWxsIC0tb3V0IHRlbXBfc3RyY29uX2ZpbHRlcmVkCgojIFN0ZXAgMjogYmd6aXAgb3V0cHV0CmJnemlwIHRlbXBfc3RyY29uX2ZpbHRlcmVkLnJlY29kZS52Y2YKCiMgU3RlcCAzOiAjIFN0ZXAgMzogQ2FsY3VsYXRlIHdpbmRvd2VkIHBpCnZjZnRvb2xzIC0tZ3p2Y2YgdGVtcF9zdHJjb25fZmlsdGVyZWQucmVjb2RlLnZjZi5neiAtLXdpbmRvdy1waSAxMDAwMCAtLW91dCBST0QuQ0FETy5zdHItY29uLnBpLndpbmRvd2VkLnBpCgojIEZvciBjb24tcm9kCiMgU3RlcCAxOiBGaWx0ZXIgVkNGIGZvciBwb3B1bGF0aW9uIHN1YnNldAp2Y2Z0b29scyAtLWd6dmNmIFNOUC5UUlNkcDEwZzEuRklMLnZjZiAtLWtlZXAgcG9wbWFwX2ZpbGVzL2Nvbi1yb2QudHh0IC0tcmVjb2RlIC0tcmVjb2RlLUlORk8tYWxsIC0tb3V0IHRlbXBfY29ucm9kX2ZpbHRlcmVkCgojIFN0ZXAgMjogYmd6aXAgb3V0cHV0CmJnemlwIHRlbXBfY29ucm9kX2ZpbHRlcmVkLnJlY29kZS52Y2YKCiMgU3RlcCAzOiBDYWxjdWxhdGUgd2luZG93ZWQgcGkKdmNmdG9vbHMgLS1nenZjZiB0ZW1wX2NvbnJvZF9maWx0ZXJlZC5yZWNvZGUudmNmLmd6IC0td2luZG93LXBpIDEwMDAwIC0tb3V0IFJPRC5DQURPLmNvbi1yb2QucGkud2luZG93ZWQucGkKCiMgRm9yIHN0ci1yb2QKIyBTdGVwIDE6IEZpbHRlciBWQ0YgZm9yIHBvcHVsYXRpb24gc3Vic2V0CnZjZnRvb2xzIC0tZ3p2Y2YgU05QLlRSU2RwMTBnMS5GSUwudmNmIC0ta2VlcCBwb3BtYXBfZmlsZXMvc3RyLXJvZC50eHQgLS1yZWNvZGUgLS1yZWNvZGUtSU5GTy1hbGwgLS1vdXQgdGVtcF9zdHJyb2RfZmlsdGVyZWQKCiMgU3RlcCAyOiBiZ3ppcCBvdXRwdXQKYmd6aXAgdGVtcF9zdHJyb2RfZmlsdGVyZWQucmVjb2RlLnZjZgoKIyBTdGVwIDM6IENhbGN1bGF0ZSB3aW5kb3dlZCBwaQp2Y2Z0b29scyAtLWd6dmNmIHRlbXBfc3Rycm9kX2ZpbHRlcmVkLnJlY29kZS52Y2YuZ3ogLS13aW5kb3ctcGkgMTAwMDAgLS1vdXQgUk9ELkNBRE8uc3RyLXJvZC5waS53aW5kb3dlZC5waQpgYGAKCiMjIyBNYWtlIHNjcmlwdCB3aXRoIGxvb3AgdXNpbmcgQ2hhdEdQVAoKIyMjIyBNYWtlIHNjcmlwdAoKYGBge2Jhc2h9CiMhL2Jpbi9iYXNoCgpWQ0Y9U05QLlRSU2RwMTBnMS5GSUwudmNmLmd6ClBPUFM9KCJjb24tY29uIiAic3RyLWNvbiIgImNvbi1yb2QiICJzdHItcm9kIikKCmZvciBQT1AgaW4gIiR7UE9QU1tAXX0iOyBkbwogICAgZWNobyAiUHJvY2Vzc2luZyAkUE9QLi4uIgoKICAgIEtFRVA9InBvcG1hcF9maWxlcy8ke1BPUH0udHh0IgogICAgT1VUX1BSRUZJWD0idGVtcF8ke1BPUC8vLX0iCiAgICBSRUNfVkNGPSIke09VVF9QUkVGSVh9LnJlY29kZS52Y2YiCiAgICBSRUNfVkNGR1o9IiR7UkVDX1ZDRn0uZ3oiCiAgICBPVVRQVVRfUEk9IlJPRC5DQURPLiR7UE9QfS5waS53aW5kb3dlZC5waSIKCiAgICAjIFN0ZXAgMTogRmlsdGVyIGFuZCByZWNvZGUKICAgIHZjZnRvb2xzIC0tZ3p2Y2YgIiRWQ0YiIFwKICAgICAgICAtLWtlZXAgIiRLRUVQIiBcCiAgICAgICAgLS1yZWNvZGUgLS1yZWNvZGUtSU5GTy1hbGwgXAogICAgICAgIC0tb3V0ICIkT1VUX1BSRUZJWCIKCiAgICAjIFN0ZXAgMjogQ29tcHJlc3MgVkNGIGFuZCByZW1vdmUgdW5jb21wcmVzc2VkCiAgICBiZ3ppcCAiJFJFQ19WQ0YiCiAgICBybSAiJFJFQ19WQ0YiCgogICAgIyBTdGVwIDM6IENhbGN1bGF0ZSB3aW5kb3dlZCBwaQogICAgdmNmdG9vbHMgLS1nenZjZiAiJFJFQ19WQ0ZHWiIgXAogICAgICAgIC0td2luZG93LXBpIDEwMDAwIFwKICAgICAgICAtLW91dCAiJE9VVFBVVF9QSSIKCiAgICAjIFN0ZXAgNDogQ2xlYW4gdXAgY29tcHJlc3NlZCBWQ0YKICAgIHJtICIkUkVDX1ZDRkdaIgoKICAgIGVjaG8gIkZpbmlzaGVkIHByb2Nlc3NpbmcgJFBPUCIKICAgIGVjaG8gIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSIKZG9uZQpgYGAKCiMjIyMgTWFrZSBleGVjdXRhYmxlCgpgYGB7YmFzaH0KY2htb2QgK3ggcnVuX3BpX2NhbGN1bGF0aW9ucy5zaApgYGAKCiMjIyMgUnVuIGluIHRtdXgKYGBge2Jhc2h9CiMgUnVuIGluIHRtdXgKdG11eCBuZXcgLXMgcGlfY2FsYwojIFJlYXR0YWNoIGxhdGVyCnRtdXggYXR0YWNoLXNlc3Npb24gLXQgcGlfY2FsYwpgYGAKCiMjIyBMb2FkIGRhdGFmcmFtZQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGkuYWxsLmRhdGFmcmFtZTwtcmVhZC50YWJsZSgiL2hvbWUvU2hhcmVkX0RhdGEvUk9EX0NBRE8vYW5hbHlzaXMvcmF3LnZjZi9ST0QuQ0FETy5hbGwucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLmNvbmNvbi5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLmNvbi1jb24ucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLmNvbnJvZC5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLmNvbi1yb2QucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLnN0cmNvbi5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLnN0ci1jb24ucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCnBpLnN0cnJvZC5kYXRhZnJhbWU8LXJlYWQudGFibGUoIi9ob21lL2pncmVlbi9ST0RfQ0FET193b3JraW5nL051Y2xlb3RpZGVfZGl2ZXJzaXR5L1JPRC5DQURPLnN0ci1yb2QucGkud2luZG93ZWQucGkud2luZG93ZWQucGkiLCBzZXA9Ilx0IiwgaGVhZGVyPVQpCmBgYAoKIyMjIENvbG9yIHBhbGV0dGUKYGBge3J9CiNIZXJlIGlzIHRoZSBjb2xvciBwYWxsZXR0ZSB0aGF0IHdlIHdpbGwgdXNlIGZvciBldmVyeXRoaW5nOgoKY29sX3BhbCA8LSBjKCIjMDA3MkIyIiwgIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjRjBFNDQyIikKCiNMZXQncyBmYWN0b3IgdHJlYXRtZW50cyBhcyBmb2xsb3dzOgoKZGYkVFJFQVQgPC0gZmFjdG9yKGRmJFRSRUFULCBsZXZlbHM9YygiQ09OQ09OIiwgIlNUUkNPTiIsICJDT05ST0QiLCAiU1RSUk9EIikpCmBgYAoKIyMjIE1vZGlmeSBDSFJPTSBjb2x1bW4gaW4gZGF0YWZyYW1lCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwaS5hbGwuZGF0YWZyYW1lICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4MC4xIiwgIjEiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgxLjEiLCAiMiIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODIuMSIsICIzIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4My4xIiwgIjQiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg0LjEiLCAiNSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODUuMSIsICI2IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Ni4xIiwgIjciKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg3LjEiLCAiOCIpKSAlPiUKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4OC4xIiwgIjkiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg5LjEiLCAiMTAiKSkgIC0+IHBpLmFsbC5kZgpwaS5hbGwuZGYkQ0hST00gPC0gYXMuZmFjdG9yKHBpLmFsbC5kZiRDSFJPTSkKCnBpLmNvbmNvbi5kYXRhZnJhbWUgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgwLjEiLCAiMSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODEuMSIsICIyIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Mi4xIiwgIjMiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgzLjEiLCAiNCIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODQuMSIsICI1IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4NS4xIiwgIjYiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg2LjEiLCAiNyIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODcuMSIsICI4IikpICU+JQogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg4LjEiLCAiOSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODkuMSIsICIxMCIpKSAgLT4gcGkuY29uY29uLmRmCnBpLmNvbmNvbi5kZiRDSFJPTSA8LSBhcy5mYWN0b3IocGkuY29uY29uLmRmJENIUk9NKQoKcGkuY29ucm9kLmRhdGFmcmFtZSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODAuMSIsICIxIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4MS4xIiwgIjIiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgyLjEiLCAiMyIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODMuMSIsICI0IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4NC4xIiwgIjUiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg1LjEiLCAiNiIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODYuMSIsICI3IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Ny4xIiwgIjgiKSkgJT4lCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODguMSIsICI5IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4OS4xIiwgIjEwIikpICAtPiBwaS5jb25yb2QuZGYKcGkuY29ucm9kLmRmJENIUk9NIDwtIGFzLmZhY3RvcihwaS5jb25yb2QuZGYkQ0hST00pCgpwaS5zdHJjb24uZGF0YWZyYW1lICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4MC4xIiwgIjEiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgxLjEiLCAiMiIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODIuMSIsICIzIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4My4xIiwgIjQiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg0LjEiLCAiNSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODUuMSIsICI2IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Ni4xIiwgIjciKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg3LjEiLCAiOCIpKSAlPiUKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4OC4xIiwgIjkiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg5LjEiLCAiMTAiKSkgIC0+IHBpLnN0cmNvbi5kZgpwaS5zdHJjb24uZGYkQ0hST00gPC0gYXMuZmFjdG9yKHBpLnN0cmNvbi5kZiRDSFJPTSkKCnBpLnN0cnJvZC5kYXRhZnJhbWUgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgwLjEiLCAiMSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODEuMSIsICIyIikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4Mi4xIiwgIjMiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1NzgzLjEiLCAiNCIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODQuMSIsICI1IikpICU+JSAKICBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgIk5DXzAzNTc4NS4xIiwgIjYiKSkgJT4lIAogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg2LjEiLCAiNyIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODcuMSIsICI4IikpICU+JQogIG11dGF0ZShDSFJPTSA9IHN0cl9yZXBsYWNlKENIUk9NLCAiTkNfMDM1Nzg4LjEiLCAiOSIpKSAlPiUgCiAgbXV0YXRlKENIUk9NID0gc3RyX3JlcGxhY2UoQ0hST00sICJOQ18wMzU3ODkuMSIsICIxMCIpKSAgLT4gcGkuc3Rycm9kLmRmCnBpLnN0cnJvZC5kZiRDSFJPTSA8LSBhcy5mYWN0b3IocGkuc3Rycm9kLmRmJENIUk9NKQpgYGAKCiMjIyBGb3IgbG9vcCB0byByZXBsYWNlIHByZXZpb3VzIGRhdGFmcmFtZSBtYW5pcHVsYXRpb24KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBDcmVhdGUgbmFtZWQgdmVjdG9yIHRvIG1hcCBjaHJvbW9zb21lIG5hbWVzCmNocm9tX21hcCA8LSBzZXROYW1lcyhhcy5jaGFyYWN0ZXIoMToxMCksIHBhc3RlMCgiTkNfMDM1NzgiLCAwOjksICIuMSIpKQoKIyBMaXN0IG9mIG9yaWdpbmFsIGRhdGFmcmFtZSBuYW1lcyAoYXMgc3RyaW5ncykKaW5wdXRfbmFtZXMgPC0gYygKICAicGkuYWxsLmRhdGFmcmFtZSIsCiAgInBpLmNvbmNvbi5kYXRhZnJhbWUiLAogICJwaS5jb25yb2QuZGF0YWZyYW1lIiwKICAicGkuc3RyY29uLmRhdGFmcmFtZSIsCiAgInBpLnN0cnJvZC5kYXRhZnJhbWUiCikKCiMgQ29ycmVzcG9uZGluZyBvdXRwdXQgZGF0YWZyYW1lIG5hbWVzCm91dHB1dF9uYW1lcyA8LSBjKAogICJwaS5hbGwuZGYiLAogICJwaS5jb25jb24uZGYiLAogICJwaS5jb25yb2QuZGYiLAogICJwaS5zdHJjb24uZGYiLAogICJwaS5zdHJyb2QuZGYiCikKCiMgTG9vcCB0aHJvdWdoIGVhY2ggZGF0YWZyYW1lCmZvciAoaSBpbiBzZXFfYWxvbmcoaW5wdXRfbmFtZXMpKSB7CiAgZGYgPC0gZ2V0KGlucHV0X25hbWVzW2ldKSAgIyByZXRyaWV2ZSB0aGUgZGF0YWZyYW1lIGJ5IG5hbWUKICAKICAjIFJlcGxhY2UgY2hyb21vc29tZSBuYW1lcwogIGZvciAob2xkIGluIG5hbWVzKGNocm9tX21hcCkpIHsKICAgIGRmIDwtIGRmICU+JSBtdXRhdGUoQ0hST00gPSBzdHJfcmVwbGFjZShDSFJPTSwgb2xkLCBjaHJvbV9tYXBbW29sZF1dKSkKICB9CiAgCiAgIyBDb252ZXJ0IHRvIGZhY3RvcgogIGRmJENIUk9NIDwtIGFzLmZhY3RvcihkZiRDSFJPTSkKICAKICAjIEFzc2lnbiB0byBuZXcgbmFtZSBpbiBnbG9iYWwgZW52aXJvbm1lbnQKICBhc3NpZ24ob3V0cHV0X25hbWVzW2ldLCBkZikKfQpgYGAKCgojIyMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcwpgYGB7cn0Kc3VtbWFyeShwaS5hbGwuZGYpCmJ5KHBpLmFsbC5kZiwgcGkuYWxsLmRmJENIUk9NLCBzdW1tYXJ5KQpjb3IocGkuYWxsLmRmJE5fVkFSSUFOVFMsIHBpLmFsbC5kZiRQSSkKCnN1bW1hcnkocGkuY29uY29uLmRmKQpieShwaS5jb25jb24uZGYsIHBpLmNvbmNvbi5kZiRDSFJPTSwgc3VtbWFyeSkKY29yKHBpLmNvbmNvbi5kZiROX1ZBUklBTlRTLCBwaS5jb25jb24uZGYkUEkpCgpzdW1tYXJ5KHBpLmNvbnJvZC5kZikKYnkocGkuY29ucm9kLmRmLCBwaS5jb25yb2QuZGYkQ0hST00sIHN1bW1hcnkpCmNvcihwaS5jb25yb2QuZGYkTl9WQVJJQU5UUywgcGkuY29ucm9kLmRmJFBJKQoKc3VtbWFyeShwaS5zdHJjb24uZGYpCmJ5KHBpLnN0cmNvbi5kZiwgcGkuc3RyY29uLmRmJENIUk9NLCBzdW1tYXJ5KQpjb3IocGkuc3RyY29uLmRmJE5fVkFSSUFOVFMsIHBpLnN0cmNvbi5kZiRQSSkKCnN1bW1hcnkocGkuc3Rycm9kLmRmKQpieShwaS5zdHJyb2QuZGYsIHBpLnN0cnJvZC5kZiRDSFJPTSwgc3VtbWFyeSkKY29yKHBpLnN0cnJvZC5kZiROX1ZBUklBTlRTLCBwaS5zdHJyb2QuZGYkUEkpCmBgYAoKIyMjIE5ldyBsb29wIGFuZCBwbG90dGluZyBmb3Igc3RhdGlzdGljcwoKYGBge3J9CmNvbF9wYWwgPC0gYygKICAiQUxMIiA9ICJncmF5NzAiLAogICJDT05DT04iID0gIiMwMDcyQjIiLCAKICAiU1RSQ09OIiA9ICIjNTZCNEU5IiwgCiAgIkNPTlJPRCIgPSAiI0U2OUYwMCIsIAogICJTVFJST0QiID0gIiNGMEU0NDIiCikKCmRmX25hbWVzIDwtIGMoInBpLmFsbC5kZiIsICJwaS5jb25jb24uZGYiLCAicGkuc3RyY29uLmRmIiwgInBpLmNvbnJvZC5kZiIsICJwaS5zdHJyb2QuZGYiKQpkZl9sYWJlbHMgPC0gYygiQUxMIiwgIkNPTkNPTiIsICJTVFJDT04iLCAiQ09OUk9EIiwgIlNUUlJPRCIpCmNocm9tX2xldmVscyA8LSBhcy5jaGFyYWN0ZXIoMToxMCkKCnN1bW1hcnlfbGlzdCA8LSBsaXN0KCkKCmZvciAoaSBpbiBzZXFfYWxvbmcoZGZfbmFtZXMpKSB7CiAgZGYgPC0gZ2V0KGRmX25hbWVzW2ldKQogIHRyZWF0IDwtIGRmX2xhYmVsc1tpXQogIAogIGRmJFRSRUFUIDwtIGZhY3Rvcih0cmVhdCwgbGV2ZWxzID0gbmFtZXMoY29sX3BhbCkpCiAgCiAgY2hyb21fc3VtbWFyeSA8LSBkZiAlPiUKICAgIGdyb3VwX2J5KENIUk9NLCBUUkVBVCkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG1lYW5fUEkgPSBtZWFuKFBJLCBuYS5ybSA9IFRSVUUpLAogICAgICBzZV9QSSA9IHNkKFBJLCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpLAogICAgICBtZWFuX05fVkFSSUFOVFMgPSBtZWFuKE5fVkFSSUFOVFMsIG5hLnJtID0gVFJVRSksCiAgICAgIHNlX05fVkFSSUFOVFMgPSBzZChOX1ZBUklBTlRTLCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApICU+JQogICAgbXV0YXRlKENIUk9NID0gZmFjdG9yKENIUk9NLCBsZXZlbHMgPSBjaHJvbV9sZXZlbHMpKQogIAogIHN1bW1hcnlfbGlzdFtbaV1dIDwtIGNocm9tX3N1bW1hcnkKfQoKc3VtbWFyeV9kZiA8LSBiaW5kX3Jvd3Moc3VtbWFyeV9saXN0KQoKbWVhbl9waV9wbG90IDwtIGdncGxvdChzdW1tYXJ5X2RmLCBhZXMoeCA9IENIUk9NLCB5ID0gbWVhbl9QSSwgZmlsbCA9IFRSRUFUKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBtZWFuX1BJIC0gc2VfUEksIHltYXggPSBtZWFuX1BJICsgc2VfUEkpLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4yKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sX3BhbCwgbmFtZSA9ICJUcmVhdG1lbnQiKSArCiAgbGFicyh0aXRsZSA9ICJNZWFuIFBJIHBlciBDaHJvbW9zb21lIiwgeCA9ICJDaHJvbW9zb21lIiwgeSA9ICJNZWFuIFBJIikgKwogIHRoZW1lX21pbmltYWwoKQoKbWVhbl9uX3Bsb3QgPC0gZ2dwbG90KHN1bW1hcnlfZGYsIGFlcyh4ID0gQ0hST00sIHkgPSBtZWFuX05fVkFSSUFOVFMsIGZpbGwgPSBUUkVBVCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbl9OX1ZBUklBTlRTIC0gc2VfTl9WQVJJQU5UUywgeW1heCA9IG1lYW5fTl9WQVJJQU5UUyArIHNlX05fVkFSSUFOVFMpLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4yKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sX3BhbCwgbmFtZSA9ICJUcmVhdG1lbnQiKSArCiAgbGFicyh0aXRsZSA9ICJNZWFuIG51bWJlciBvZiB2YXJpYW50cyBwZXIgQ2hyb21vc29tZSIsIHggPSAiQ2hyb21vc29tZSIsIHkgPSAiTWVhbiAjIHZhcmlhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKQoKcHJpbnQobWVhbl9waV9wbG90KQpwcmludChtZWFuX25fcGxvdCkKCmdnc2F2ZSgibWVhbl9waV9wbG90LnBuZyIsIHBsb3QgPSBtZWFuX3BpX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKZ2dzYXZlKCJtZWFuX25fdmFyaWFudHNfcGxvdC5wbmciLCBwbG90ID0gbWVhbl9uX3Bsb3QsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKCmBgYAoKIyBDb3JyZWxhdGlvbiB2aXN1YWxpemF0aW9ucwpgYGB7cn0KZm9yIChpIGluIHNlcV9hbG9uZyhkZl9uYW1lcykpIHsKICBkZiA8LSBnZXQoZGZfbmFtZXNbaV0pCiAgbGFiZWwgPC0gZGZfbGFiZWxzW2ldCiAgCiAgcCA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gTl9WQVJJQU5UUywgeSA9IFBJKSkgKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNCkgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmx1ZSIpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiQ29ycmVsYXRpb246IFBJIHZzICMgdmFyaWFudHMg4oCUIiwgbGFiZWwpLAogICAgICAgICB4ID0gIk5fVkFSSUFOVFMiLAogICAgICAgICB5ID0gIlBJIikgKwogICAgdGhlbWVfbWluaW1hbCgpCiAgCiAgcHJpbnQocCkKfQpgYGAKCiMjIyBUYWJsZSBvZiBjb3JyZWxhdGlvbnMKCmBgYHtyfQpjb3JfdGFibGUgPC0gdGliYmxlKAogIGRhdGFzZXQgPSBkZl9sYWJlbHMsCiAgY29ycmVsYXRpb24gPSBtYXBfZGJsKGRmX25hbWVzLCB+IGNvcihnZXQoLngpJE5fVkFSSUFOVFMsIGdldCgueCkkUEksIHVzZSA9ICJjb21wbGV0ZS5vYnMiKSkKKQoKcHJpbnQoY29yX3RhYmxlKQpgYGAKCiMjIyBQbG90IFBJIGJ5IGNocm9tb3NvbWUKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChwaS5hbGwuZGYsIGFlcyh4PUNIUk9NLCB5PVBJLCkpKwogIGdlb21fdmlvbGluKGFlcyhjb2xvcj1DSFJPTSxmaWxsPUNIUk9NKSkrCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPUNIUk9NKSwgd2lkdGg9MC4xLG91dGxpZXIuc2hhcGUgPSAyMywgb3V0bGllci5jb2xvciA9ICJibGFjayIpKwogIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0yMywgc2l6ZT0yKSsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpKwogIHRoZW1lX2NsYXNzaWMoKQpgYGAKCiMjIyBQbG90IFBJIGJ5IGNocm9tb3NvbWUgbG9vcAoKYGBge3J9CiMgTGlzdCBvZiBkYXRhZnJhbWVzIGFuZCBsYWJlbHMKZGZfbmFtZXMgPC0gYygicGkuYWxsLmRmIiwgInBpLmNvbmNvbi5kZiIsICJwaS5jb25yb2QuZGYiLCAicGkuc3RyY29uLmRmIiwgInBpLnN0cnJvZC5kZiIpCmRmX2xhYmVscyA8LSBjKCJBbGwiLCAiQ29uQ29uIiwgIkNvblJvZCIsICJTdHJDb24iLCAiU3RyUm9kIikKCiMgU3RhbmRhcmQgY2hyb21vc29tZSBvcmRlcgpjaHJvbV9sZXZlbHMgPC0gYXMuY2hhcmFjdGVyKDE6MTApCgojIENvbWJpbmUgYWxsIGludG8gb25lIGRhdGFmcmFtZQpjb21iaW5lZF9kZiA8LSBwdXJycjo6bWFwMl9kZnIoZGZfbmFtZXMsIGRmX2xhYmVscywgZnVuY3Rpb24oZGZfbmFtZSwgbGFiZWwpIHsKICBkZiA8LSBnZXQoZGZfbmFtZSkKICBkZiAlPiUKICAgIG11dGF0ZSgKICAgICAgZGF0YXNldCA9IGxhYmVsLAogICAgICBDSFJPTSA9IGZhY3RvcihDSFJPTSwgbGV2ZWxzID0gY2hyb21fbGV2ZWxzKQogICAgKQp9KQoKIyBGYWNldGVkIHZpb2xpbiArIGJveHBsb3QKZ2dwbG90KGNvbWJpbmVkX2RmLCBhZXMoeCA9IENIUk9NLCB5ID0gUEkpKSArCiAgZ2VvbV92aW9saW4oYWVzKGNvbG9yID0gQ0hST00sIGZpbGwgPSBDSFJPTSksIHRyaW0gPSBGQUxTRSkgKwogIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IENIUk9NKSwgd2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSAyMywgb3V0bGllci5jb2xvciA9ICJibGFjayIpICsKICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gMjMsIHNpemUgPSAyKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJQYWlyZWQiKSArCiAgbGFicyh0aXRsZSA9ICJQSSBEaXN0cmlidXRpb24gYnkgQ2hyb21vc29tZSAoRmFjZXRlZCBieSBEYXRhc2V0KSIsCiAgICAgICB4ID0gIkNocm9tb3NvbWUiLCB5ID0gIlBJIikgKwogIGZhY2V0X3dyYXAofiBkYXRhc2V0LCBuY29sID0gMikgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKYGBgCgojIyMgU21hbGxlciB2aXN1YWxpemF0aW9ucwpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KaGlzdChteWRmJFBJLGJyPTQwKQoKYm94cGxvdChteWRmJFBJLCB5bGFiPSJOdWMgRGl2ZXJzaXR5IikKYGBgCgojIyMgUGxvdCBCeSBwb3NpdGlvbgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KHBpLmFsbC5kZiwgYWVzKHg9QklOX1NUQVJULCB5PVBJLCBjb2xvcj1DSFJPTSkpKwogIGdlb21fcG9pbnQoKSsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfbnVtYmVyKHNjYWxlID0gMWUtNiwgc3VmZml4ID0gIk0iKSkgKwogIGZhY2V0X3dyYXAofkNIUk9NKSsKICB0aGVtZV9jbGFzc2ljKCkKYGBgCiMjIyBMb29wIGZvciBwbG90IGJ5IHBvc2l0aW9uCmBgYHtyfQojIERlZmluZSBkYXRhZnJhbWUgbmFtZXMgYW5kIGxhYmVscwpkZl9uYW1lcyA8LSBjKCJwaS5hbGwuZGYiLCAicGkuY29uY29uLmRmIiwgInBpLmNvbnJvZC5kZiIsICJwaS5zdHJjb24uZGYiLCAicGkuc3Rycm9kLmRmIikKZGZfbGFiZWxzIDwtIGMoIkFMTCIsICJDT05DT04iLCAiQ09OUk9EIiwgIlNUUkNPTiIsICJTVFJST0QiKQoKIyBHZXQgZ2xvYmFsIFBJIHJhbmdlCmFsbF9waV92YWx1ZXMgPC0gdW5saXN0KGxhcHBseShkZl9uYW1lcywgZnVuY3Rpb24oeCkgZ2V0KHgpJFBJKSkKZ2xvYmFsX3ltaW4gPC0gbWluKGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKZ2xvYmFsX3ltYXggPC0gbWF4KGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKCiMgTG9vcCBvdmVyIGRhdGFmcmFtZXMKZm9yIChpIGluIHNlcV9hbG9uZyhkZl9uYW1lcykpIHsKICBkZiA8LSBnZXQoZGZfbmFtZXNbaV0pCiAgbGFiZWwgPC0gZGZfbGFiZWxzW2ldCiAgCiAgIyBFbnN1cmUgQ0hST00gaXMgYSBmYWN0b3Igb3JkZXJlZCBmcm9tIDEgdG8gMTAKICBkZiRDSFJPTSA8LSBmYWN0b3IoZGYkQ0hST00sIGxldmVscyA9IGFzLmNoYXJhY3RlcigxOjEwKSkKICAKICBwIDwtIGdncGxvdChkZiwgYWVzKHggPSBCSU5fU1RBUlQsIHkgPSBQSSwgY29sb3IgPSBDSFJPTSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBmYWNldF93cmFwKH5DSFJPTSkgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJQYWlyZWQiKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbGFiZWxfbnVtYmVyKHNjYWxlID0gMWUtNiwgc3VmZml4ID0gIk0iKSkgKyAgIyBIdW1hbiByZWFkYWJsZSB4LWF4aXMKICAgIHlsaW0oZ2xvYmFsX3ltaW4sIGdsb2JhbF95bWF4KSArICAjIFNhbWUgeS1heGlzIGZvciBhbGwgcGxvdHMKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIlBJIHZzIEJJTl9TVEFSVCAtIiwgbGFiZWwpLAogICAgICAgICB4ID0gIkJJTl9TVEFSVCAobWlsbGlvbnMpIiwKICAgICAgICAgeSA9ICJQSSIpCiAgCiAgcHJpbnQocCkKICAKICBnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoIlBJX3ZzX0JJTl9TVEFSVF8iLCBsYWJlbCwgIi5wbmciKSwKICAgICAgICAgcGxvdCA9IHAsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCkKfQoKYGBgCgojIyMgRmFjZXQgd3JhcCBjaHJvbW9zb21lIHNob3dpbmcgdGhlbSBhY3Jvc3MgZGlmZmVyZW50IHRyZWF0bWVudCB0eXBlcwpgYGB7cn0KIyBEZWZpbmUgZGF0YWZyYW1lIG5hbWVzIGFuZCBsYWJlbHMKZGZfbmFtZXMgPC0gYygicGkuYWxsLmRmIiwgInBpLmNvbmNvbi5kZiIsICJwaS5jb25yb2QuZGYiLCAicGkuc3RyY29uLmRmIiwgInBpLnN0cnJvZC5kZiIpCmRmX2xhYmVscyA8LSBjKCJBTEwiLCAiQ09OQ09OIiwgIkNPTlJPRCIsICJTVFJDT04iLCAiU1RSUk9EIikKCiMgQ3VzdG9tIGNvbG9yIHBhbGV0dGUKY29sX3BhbCA8LSBjKAogICJBTEwiID0gImdyYXk3MCIsCiAgIkNPTkNPTiIgPSAiIzAwNzJCMiIsIAogICJTVFJDT04iID0gIiM1NkI0RTkiLCAKICAiQ09OUk9EIiA9ICIjRTY5RjAwIiwgCiAgIlNUUlJPRCIgPSAiI0YwRTQ0MiIKKQoKIyBDb21iaW5lIGFsbCBkYXRhIGludG8gb25lIGRhdGFmcmFtZSB3aXRoIHRyZWF0bWVudCBsYWJlbHMKYWxsX2RhdGEgPC0gYmluZF9yb3dzKGxhcHBseShzZXFfYWxvbmcoZGZfbmFtZXMpLCBmdW5jdGlvbihpKSB7CiAgZGYgPC0gZ2V0KGRmX25hbWVzW2ldKQogIGRmJFRyZWF0bWVudCA8LSBkZl9sYWJlbHNbaV0KICBkZgp9KSkKCiMgU2V0IENIUk9NIGFuZCBUcmVhdG1lbnQgYXMgb3JkZXJlZCBmYWN0b3JzCmFsbF9kYXRhJENIUk9NIDwtIGZhY3RvcihhbGxfZGF0YSRDSFJPTSwgbGV2ZWxzID0gYXMuY2hhcmFjdGVyKDE6MTApKQphbGxfZGF0YSRUcmVhdG1lbnQgPC0gZmFjdG9yKGFsbF9kYXRhJFRyZWF0bWVudCwgbGV2ZWxzID0gZGZfbGFiZWxzKQoKIyBHZXQgZ2xvYmFsIFBJIHJhbmdlCmdsb2JhbF95bWluIDwtIG1pbihhbGxfZGF0YSRQSSwgbmEucm0gPSBUUlVFKQpnbG9iYWxfeW1heCA8LSBtYXgoYWxsX2RhdGEkUEksIG5hLnJtID0gVFJVRSkKCiMgTG9vcCB0aHJvdWdoIGNocm9tb3NvbWVzIDEgdG8gMTAKZm9yIChjaHIgaW4gMToxMCkgewogIGNocl9zdHIgPC0gYXMuY2hhcmFjdGVyKGNocikKICBjaHJfZGF0YSA8LSBmaWx0ZXIoYWxsX2RhdGEsIENIUk9NID09IGNocl9zdHIpCiAgCiAgcCA8LSBnZ3Bsb3QoY2hyX2RhdGEsIGFlcyh4ID0gQklOX1NUQVJULCB5ID0gUEksIGNvbG9yID0gVHJlYXRtZW50KSkgKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNiwgc2l6ZSA9IDAuNSkgKwogICAgZmFjZXRfd3JhcCh+VHJlYXRtZW50LCBucm93ID0gMSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbF9wYWwpICsKICAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9udW1iZXIoc2NhbGUgPSAxZS02LCBzdWZmaXggPSAiTSIpKSArCiAgICB5bGltKGdsb2JhbF95bWluLCBnbG9iYWxfeW1heCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gcGFzdGUoIkNocm9tb3NvbWUiLCBjaHIsICItIFBJIGFjcm9zcyBUcmVhdG1lbnQgVHlwZXMiKSwKICAgICAgeCA9ICJCSU5fU1RBUlQgKG1pbGxpb25zKSIsCiAgICAgIHkgPSAiUEkiCiAgICApCiAgCiAgcHJpbnQocCkKICAKICBnZ3NhdmUoCiAgICBmaWxlbmFtZSA9IHBhc3RlMCgiUElfY2hyIiwgY2hyLCAiX2Fjcm9zc190cmVhdG1lbnRzLnBuZyIpLAogICAgcGxvdCA9IHAsCiAgICB3aWR0aCA9IDE2LAogICAgaGVpZ2h0ID0gNCwKICAgIGRwaSA9IDMwMAogICkKfQoKYGBgCiMjIyBPbmx5IGNocm9tb3NvbWUgMQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBTdWJzZXQgYnkgY2hyb20KbXlkZi5jaHIxIDwtIG15ZGZbd2hpY2gobXlkZiRDSFJPTT09IjEiKSxdCgpnZ3Bsb3QobXlkZi5jaHIxLCBhZXMoeD1CSU5fU1RBUlQsIHk9UEkpKSsKICBnZW9tX3BvaW50KCkrCiAgdGhlbWVfY2xhc3NpYygpCmBgYAoKYGBge3J9CiMgTGlzdCBvZiB0cmVhdG1lbnQgZGF0YSBmcmFtZXMgYW5kIHRoZWlyIGxhYmVscwpkZl9uYW1lcyA8LSBjKCJwaS5hbGwuZGYiLCAicGkuY29uY29uLmRmIiwgInBpLmNvbnJvZC5kZiIsICJwaS5zdHJjb24uZGYiLCAicGkuc3Rycm9kLmRmIikKZGZfbGFiZWxzIDwtIGMoIkFMTCIsICJDT05DT04iLCAiQ09OUk9EIiwgIlNUUkNPTiIsICJTVFJST0QiKQoKIyBTdGVwIDE6IENhbGN1bGF0ZSBnbG9iYWwgUEkgcmFuZ2UgYWNyb3NzIGFsbCBkYXRhZnJhbWVzCmFsbF9waV92YWx1ZXMgPC0gdW5saXN0KGxhcHBseShkZl9uYW1lcywgZnVuY3Rpb24oeCkgZ2V0KHgpJFBJKSkKZ2xvYmFsX3ltaW4gPC0gbWluKGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKZ2xvYmFsX3ltYXggPC0gbWF4KGFsbF9waV92YWx1ZXMsIG5hLnJtID0gVFJVRSkKCiMgU3RlcCAyOiBDcmVhdGUgcGxvdHMgYW5kIHNhdmUgYXMgUE5Hcwpmb3IgKGogaW4gc2VxX2Fsb25nKGRmX25hbWVzKSkgewogIGRmIDwtIGdldChkZl9uYW1lc1tqXSkKICBsYWJlbCA8LSBkZl9sYWJlbHNbal0KICAKICBmb3IgKGkgaW4gMToxMCkgewogICAgY2hyX2RhdGEgPC0gZGZbZGYkQ0hST00gPT0gYXMuY2hhcmFjdGVyKGkpLCBdCiAgICAKICAgIHAgPC0gZ2dwbG90KGNocl9kYXRhLCBhZXMoeCA9IEJJTl9TVEFSVCwgeSA9IFBJKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICBnZ3RpdGxlKHBhc3RlKCJUcmVhdG1lbnQ6IiwgbGFiZWwsICItIENocm9tb3NvbWUiLCBpKSkgKwogICAgICBsYWJzKHggPSAiQklOX1NUQVJUIiwgeSA9ICJQSSIpICsKICAgICAgeWxpbShnbG9iYWxfeW1pbiwgZ2xvYmFsX3ltYXgpCiAgICAKICAgIGZpbGVuYW1lIDwtIHBhc3RlMCgiUElfIiwgbGFiZWwsICJfY2hyIiwgaSwgIi5wbmciKQogICAgZ2dzYXZlKGZpbGVuYW1lID0gZmlsZW5hbWUsIHBsb3QgPSBwLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUsIGRwaSA9IDMwMCkKICB9Cn0KCmBgYAoKCiMgUnVucyBvZiBob21venlnb3NpdHkKClJ1bnMgb2YgaG9tb3p5Z29zaXR5IChST0gpIGFyZSBjb250aWd1b3VzIGxlbmd0aHMgb2YgaG9tb3p5Z291cyBnZW5vdHlwZXMgdGhhdCBhcmUgcHJlc2VudCBpbiBhbiBpbmRpdmlkdWFsIGR1ZSB0byBwYXJlbnRzIHRyYW5zbWl0dGluZyBpZGVudGljYWwgaGFwbG90eXBlcyB0byB0aGVpciBvZmZzcHJpbmcuCgpUaGUgcG90ZW50aWFsIG9mIHByZWRpY3Rpbmcgb3IgZXN0aW1hdGluZyBpbmRpdmlkdWFsIGF1dG96eWdvc2l0eSBmb3IgYSBzdWJwb3B1bGF0aW9uIGlzIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSBhdXRvc29tYWwgZ2Vub21lIGFib3ZlIGEgc3BlY2lmaWVkIGxlbmd0aCwgdGVybWVkIEZyb2guCgpUaGlzIHRlY2huaXF1ZSBjYW4gYmUgdXNlZCB0byBpZGVudGlmeSB0aGUgZ2Vub21pYyBmb290cHJpbnQgb2YgaW5icmVlZGluZyBpbiBjb25zZXJ2YXRpb24gcHJvZ3JhbXMsIGFzIG9yZ2FuaXNtcyB0aGF0IGhhdmUgdW5kZXJnb25lIHJlY2VudCBpbmJyZWVkaW5nIHdpbGwgZXhoaWJpdCBsb25nIHJ1bnMgb2YgaG9tb3p5Z29zaXR5LiBUaGUgZWZmZWN0IG9mIGluYnJlZWRpbmcgaW4gdGhlIHJlc3VsdGluZyBzdWItcG9wdWxhdGlvbnMgY291bGQgYmUgc3R1ZGllZCBieSBtZWFzdXJpbmcgdGhlIHJ1bnMgb2YgaG9tb3p5Z29zaXR5IGluIGRpZmZlcmVudCBpbmRpdmlkdWFscy4KCiMjIFN0YXJ0IFJPSCB3b3JrZmxvdwoKYGBge2Jhc2h9CnZjZnRvb2xzIC0tdmNmIFNOUC5UUlNkcDEwZzEuRklMLnZjZiAtLUxST0ggLS1vdXQgUk9ELkNBRE8uYWxsLkxST0gKYGBgCgo=